package org.luxor.commons.excel;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.read.builder.ExcelReaderBuilder;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.google.common.collect.Lists;
import org.apache.poi.ss.formula.functions.T;
import org.luxor.commons.excel.component.data.NoticeSheet;
import org.springframework.util.StringUtils;

import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * This is actually {@link EasyExcelFactory}, and short names look better.
 *
 * @author Mr.Yan
 */
public class ExcelUtils extends EasyExcelFactory {

    /**
     * 同步读取Excel的第0个Sheet中的数据 (不推荐使用，如果数据量大会把数据放到内存里面)
     *
     * @param input excel 要读的Excel文件流
     * @param clazz 数据类型
     * @return 读出的数据集
     */
    public static <T> List<T> syncReadAll(InputStream input, ExcelTypeEnum excelType, Class clazz) {
        return ExcelUtils.syncReadAll(input, excelType, clazz, null);
    }

    /**
     * 同步读取Excel的第0个Sheet中的数据 (不推荐使用，如果数据量大会把数据放到内存里面)
     *
     * @param input    excel 要读的Excel文件流
     * @param password excel打开密码
     * @param clazz    数据类型
     * @return 读出的数据集
     */
    public static <T> List<T> syncReadAll(InputStream input, ExcelTypeEnum excelType, Class clazz, String password) {
        ExcelReaderBuilder builder = EasyExcelFactory.read(input).head(clazz)
                .excelType(excelType)
                .ignoreEmptyRow(true)
                .autoCloseStream(true)
                .autoTrim(true);
        if (StringUtils.hasText(password)) {
            builder.password(password);
        }
        return builder.doReadAllSync();
    }

    /**
     * 异步读取Excel的第0个Sheet中的数据 (强烈推荐)
     *
     * @param input    excel 要读的Excel文件流
     * @param clazz    数据类型
     * @param listener 解析监听器
     */
    public static void readAll(InputStream input, ExcelTypeEnum excelType, Class clazz, ReadListener<T> listener) {
        ExcelUtils.readAll(input, excelType, clazz, listener, null);
    }

    /**
     * 异步读取Excel的第0个Sheet中的数据 (强烈推荐)
     *
     * @param input    excel 要读的Excel文件流
     * @param password excel打开密码
     * @param clazz    数据类型
     * @param listener 解析监听器
     */
    public static void readAll(InputStream input, ExcelTypeEnum excelType, Class clazz, ReadListener<T> listener, String password) {
        ExcelReaderBuilder builder = EasyExcelFactory.read(input, listener).head(clazz)
                .excelType(excelType)
                .ignoreEmptyRow(true)
                .autoCloseStream(true)
                .autoTrim(true);
        if (StringUtils.hasText(password)) {
            builder.password(password);
        }
        builder.doReadAll();
    }

    /**
     * 同步写出数据到Excel的第0个Sheet中
     *
     * @param output 输出流
     * @param data   数据集合
     * @param clazz  数据类型
     * @return java.io.OutputStream
     */
    public static void writeData(OutputStream output, List data, Class clazz) {
        ExcelWriter excelWriter = null;
        try {
            excelWriter = EasyExcelFactory.write(output).autoCloseStream(true).autoTrim(true).build();
            // 数据内容
            WriteSheet dataSheet = EasyExcel.writerSheet(0, "数据内容").head(clazz).build();
            excelWriter.write(data, dataSheet);
            // 填写须知
            writeNoticeSheet(excelWriter, 1);
        } finally {
            if (excelWriter != null) {
                excelWriter.finish();
            }
        }
    }

    /**
     * 同步生成Excel数据填写模版
     *
     * @param output Excel模版文件流
     * @param clazz  数据类型
     */
    public static void writeTemplate(OutputStream output, Class clazz) {
        ExcelWriter excelWriter = null;
        try {
            excelWriter = EasyExcelFactory.write(output).autoCloseStream(true).inMemory(true).autoTrim(true).build();
            // 数据模版
            WriteSheet dataSheet = EasyExcel.writerSheet(0, "数据模板").head(clazz).build();
            excelWriter.write(Lists.newArrayList(), dataSheet);
            // 填写须知
            writeNoticeSheet(excelWriter, 1);
        } finally {
            if (excelWriter != null) {
                excelWriter.finish();
            }
        }
    }

    private static void writeNoticeSheet(ExcelWriter excelWriter, Integer sheetNo) {
        WriteSheet noticeSheet = EasyExcel.writerSheet(sheetNo, "填写须知")
                .head(NoticeSheet.class).automaticMergeHead(true).build();
        List<NoticeSheet> noticeData = new ArrayList<>();
        noticeData.add(new NoticeSheet("1、不能对灰色表头的'字段内容'和'字段顺序'进行增加、删除或修改；"));
        noticeData.add(new NoticeSheet("2、不能在该Excel表中，对分类字段(如:状态码、性别)进行增加、删除或修改；"));
        noticeData.add(new NoticeSheet("3、Excel中红色字段为必填,黑色字段为选填，字段值请不要有“，”字符；"));
        noticeData.add(new NoticeSheet("4、Boolean类型字段中，内容'1'或者'true'字符代表TRUE、内容'0'或者'false'字符代表FALSE；"));
        noticeData.add(new NoticeSheet("5、建议单次操作数据量在3万以内，如不可避免需要操作大的数据量，请务必提前告知系统管理员,否则后果自负"));
        excelWriter.write(noticeData, noticeSheet);
    }

}
